[ Prev Page | Goto Content | Next Page ] =/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\=/=\ ========================== Wordlist password attacker ========================== Мне кажется каждый в своей жизни должен написать программу такого рода. Я не буду лишать вас такого удовольствия, я только лишь покажу как можно это сделать немного лучше (или хуже :). Итак, не долго думая, напишем многопоточный переборщик паролей по словарю. Наша программа будет поддерживать два протокола: POP3 и FTP. Я выбрал именно их, т.к. работают они одинаково (при авторизации) и широко применяются. Так что есть поле для экспериментов :) Но для начала рассмотрим что вообще такое процессы и треды. 1. О процессах и тредах Чтобы не заморачиваться на счет перевода главных терминов, будем использовать простое "перечитывание" английского слова на русский манер :) Т.е. 'process' будем звать процессом, а 'thread' будем звать тредом (в литературе так же известным как поток или нить). Не буду подробно останавливаться на теоретической части. Все это везде и по многу раз описывалось и переписывалось. Я лишь напомню основные моменты. Во всех известных мне многозадачных системах в качестве некой единицы вычисления служит процесс. Само понятие процесса абстрактно и включает в себя множество вещей. Под процессом принято считать некоторое адресное пространство, в котором выполняется по крайней мере один тред. Так же в понятие процесса входит выполняемая программа, ее данные, стек, системная информация и многое другое. Процесс в памяти и программа на диске - это далеко не одно и то же! Многозадачность системы реализовывается в виде последовательной передачи процессорного времени каждому треду всех процессов системы. Т.е. если говорить проще: система выделяет каждому треду определенный квант времени, в течение которого выполняется код. При смене выполняемых процессов происходит так называемое "переключение контекста": перенастройка указателя команд, стека, системных структур и других вещей. При создании процесса, система автоматически создает внутри него главный (или ведущий) тред. В дальнейшем именно он занимается созданием новых ведомых процессов/тредов. При создании процесса программным путем (функцией fork()), система создаст точную копию текущего процесса. Т.е. все дескрипторы, глобальные переменные и другие вещи КОПИРУЮТСЯ! При создании же треда внутри процесса все глобальные переменные и дескрипторы используются СОВМЕСТНО между этими тредами. Преимущество тредов и заключается в такой возможности совместного доступа к определенному участку памяти. Главный минус тредов - если в одном месте произошла ошибка, аварийно завершится весь процесс, а не единственный тред. 2. О многопроцессовом/многопоточном программировании Главный (ведущий) тред может создать ведомые (child) процессы или треды. Рассмотрим эту возможность подробнее (здесь и далее имеются в виду только Unix-подобные системы). Для того, чтобы создать новый процесс, как я уже и говорил, используется системная функция fork(). Она создает точную копию всего ведущего процесса и выполнение программы продолжается. Чтобы заменить выполняемую программу в ведомом процессе служит функция execve(), которая начисто переписывает процесс новой, указанной в качестве параметра, программой. Для завершения работы процесса служит функция exit(). Иногда случается так, что после завершения работы ведомого процесса в системных таблицах остается информация о нем. Такие некорректно завершившиеся процессы называются процессами-зомби. Чтобы избежать таких ситуаций, в главной программе нужно вызывать функцию wait3 для их окончательного убиения :) Данную функцию нужно использовать после поступления сигнала SIGCHLD от дочернего процесса. Треды в Linux создаются путем вызова функции pthread_create, в основе которой (и, кстати, fork() тоже) лежит известная функция clone(). Для завершения его же служит функция pthread_exit(). Так как каждый тред может разделять с остальными некий определенный участок памяти, иногда возникает такая нехорошая вещь, когда оба треда попытаются получить доступ к данным, которые содержатся по этим адресам. Что приведет к плачевным результатам :) Чтобы огородить себя любимого от этого, нужно использовать такие механизмы как мьютексы, семафоры и условные переменные. Все это так же служит и для синхронизации тредов. 1) "Мьютекс используется для взаимно-исключающего доступа к данным", т.е. если заблокировать данный мьютекс, то те данные, которые он защищает, будут недоступны ни одному треду до тех пор, пока его не разблокировать. 2) Семафор обобщает понятие мьютекса и применяется в том случае, если доступен не один, а определенное количество копий данного ресурса. 3) Условные переменные используются в том случае, если при доступе к данным, защищенным мьютексом, требуется определенное условие. Т.е. сначала блокируется мьютекс, проверяется нужное условие и если оно ложно - мьютекс немедленно освобождается до лучших времен. Преимущество условных переменных в том, что требуемые действия выполняются намного быстрее, нежели если бы мы делали это сами. Вот впринципе и все, что нам нужно знать, чтобы писать простенькие программы. За большей информацией читайте книжки по этой теме. Или проще: RTFM!! =) 3. Код Все что нам нужно сделать, чтобы проверить правильность пароля на удаленном сервере - это приконнектиться к нему, отправить имя и пароль на сервер и проверить ответ. ВСЕ!! Ничего сложного нет. В архиве вы найдете исходники программы. Я старался подробно комментировать каждое действие, так что может даже показаться, что за этими комментариями не видно строчек кода =) Но это наверное к лучшему. Опишу основные структуры, которые используются. struct serv_answers{ int port; //Порт char* answ_1; //Первый ответ (подтверждение имени пользователя) char* answ_2; //Второй ответ (о правильности пароля) }; Данная структура - есть итог диалога между клиентом (нашей программой) и сервером. Это некая универсальная вещь, которая помогает легко расширять программу и добавлять новые протоколы. struct serv_answers answers[] = { {110, "+", "+"}, //POP3 {21, "331", "230"}, //FTP {0, "", ""} //Пустой (нужно для корректного завершения) }; А это массив структур, который везже и используется. Чтобы добавить новый протокол, нужно просто добавить новую запись в данный массив и все! Правда желаемое не всегда превращается в действительное, т.к. некоторые протоколы имеют свойство все делать не так, как хочется нам. Поэтому иногда придется писать дополнительные проверки и дополнения. Но это не должно вас остановить =) И последнее: struct{ pthread_mutex_t st_mutex; //Мьютекс FILE* fhandle; //Файл с паролями struct sockaddr_in addr; //Нужно для connect int num; //Количество действующих тредов char username[32]; //Имя пользователя } thread_data; Эта структура, которую используют все созданные треды. Первое поле - это как раз тот самый мьютекс, который нужно блокировать до того, как будут изменены/добавлены данные. Все остальное - в исходниках. Удачи в изучении! dzen (dzen@inbox.ru) [ Prev Page | Goto Content | Next Page ]